package struts.ext.base;


import java.util.Collection;

import javax.servlet.ServletException;

import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionServlet;
import org.apache.struts.action.PlugIn;
import org.apache.struts.config.ActionConfig;
import org.apache.struts.config.FormBeanConfig;
import org.apache.struts.config.ForwardConfig;
import org.apache.struts.config.ModuleConfig;

import struts.ext.annotation.Action;
import struts.ext.annotation.Forward;
import struts.ext.annotation.Forwards;
import struts.ext.commons.lang.reflect.ClassWrapper;
import struts.ext.util.Arrays;
import struts.ext.util.ClassFilter;
import struts.ext.util.ClassScaner;
import struts.ext.util.Lang;
import struts.ext.util.MyActionAnnotationClassFilter;
import struts.ext.util.Strings;


/**
 * 让Struts1支持Annotation的插件
 * 
 * 注：
 * ActionServlet的init方法执行到initPlugin方法的时候会执行插件的init方法。
 * @author 
 *
 */
public class StrutsAnnotationsSupportPlugin implements PlugIn {
	
	private String actionPackages;
	private String filter;

	public void destroy() {
		
	}
    
	public void init(ActionServlet servlet, ModuleConfig config)
			throws ServletException {
		Collection<Class<?>> actionClasses = null;
		try {
			ClassScaner scanner = 
						new ClassScaner(
								servlet.getServletContext().getRealPath("WEB-INF/classes"), 
								Thread.currentThread().getContextClassLoader(), 
								getSearchPaths());
			actionClasses = scanner.list(getActionFilter());
		} catch (ClassNotFoundException e) {
			// This should never happen, because it would mean that there are
			// class files under WEB-INF/classes that can't be loaded through
			// the application classloader (breaks Servlet specification)
			throw Lang.wrapThrow(e,e.getMessage());
		}
		if(actionClasses != null){
			System.out.println("[[[[struts1-ext 提示：]]]]Find " + actionClasses.size() + " Action(s) with @Action annotation totally!");
		}
		for (Class<?> clazz : actionClasses) {
			try {
				updateActionConfig(clazz, config);
			} catch (IllegalAccessException e) {
				throw Lang.wrapThrow(e,e.getMessage());
			}
		}
	}

	private void updateActionConfig(Class<?> clazz, ModuleConfig moduleConfig)
			throws IllegalAccessException {
		Action config = clazz.getAnnotation(Action.class);	
		if (config == null) {			
			return;
		}
		
		ActionMapping actionConfig = new ActionMapping();
		actionConfig.setPath(Strings.nvl(config.path(),clazz.getSimpleName()));
		actionConfig.setType(clazz.getCanonicalName());
		actionConfig.setParameter(config.parameter());
		actionConfig.setInput(Strings.nvl(config.input(),null));		
		actionConfig.setScope(config.scope());
		actionConfig.setValidate(config.validate());
		actionConfig.setName(config.name());
		actionConfig.setCancellable(config.cancellable());	
		updateFormConfig(config, actionConfig, moduleConfig);		
		
		Forwards forwards = clazz.getAnnotation(Forwards.class);	
		Forward[] forwardArray 	= (forwards==null? config.forwards():forwards.value());		
		if (Arrays.isNotEmpty(forwardArray)) {
			for (Forward f:forwardArray) 
				updateForwardConfig(f,actionConfig);
		}
		moduleConfig.addActionConfig(actionConfig);
	}


	private void updateFormConfig(Action actionMapping,
								  ActionConfig actionConfig, 
								  ModuleConfig moduleConfig) {
		// Action without form isn't something unusual
		String formName = actionMapping.name();
		//如果没有设置name而且form使用的是默认的ActionForm，相当于没有做任何配置，就不生成Form
		if (Strings.isBlank(formName) && ClassWrapper.wrap(ActionForm.class).is(actionMapping.form())
				) {
			return;
		}
		
		// struts-config.xml can't be overridden and 
		FormBeanConfig formConfig = moduleConfig.findFormBeanConfig(formName);
		if (formConfig != null || ActionForm.class.equals(actionMapping.form())) {
			actionConfig.setName(formName);
			return;
		}
		
		String formClassName = actionMapping.form().getCanonicalName();
		if (Strings.isBlank(formName)) {
			formName = formClassName;
		}
		actionConfig.setName(formName);
		formConfig = new FormBeanConfig();
		formConfig.setName(formName);
		formConfig.setType(formClassName);
		moduleConfig.addFormBeanConfig(formConfig);
	}
	
	private void updateForwardConfig(Forward actionForward, ActionConfig actionConfig)
			throws IllegalAccessException {
		if (actionForward == null) {
			return;
		}

		ForwardConfig forwardConfig = new org.apache.struts.action.ActionForward();
 
		forwardConfig.setName(actionForward.name());
		forwardConfig.setPath(actionForward.path());
		forwardConfig.setRedirect(actionForward.redirect());
		actionConfig.addForwardConfig(forwardConfig);
	}
	
	private ClassFilter getActionFilter() {
		if (Strings.isNotBlank(filter)){
			return (ClassFilter) ClassWrapper.wrapByName(filter).newOne();
		}
		return new MyActionAnnotationClassFilter();
	}
	
	private String[] getSearchPaths() {
		if (Strings.isNotEmpty(actionPackages)) {
			if (Strings.contains(actionPackages, ","))
				return Strings.split(actionPackages, ",");
			return new String[]{actionPackages};
		}
		return null;
	}
	
	public String getActionPackages() {
		return actionPackages;
	}
	public void setActionPackages(String actionPackages) {
		this.actionPackages = actionPackages;
	}

	public void setFilter(String filter) {
		this.filter = filter;
	}

	public String getFilter() {
		return filter;
	}
	
}
